package com.gggd.aopdemo.aop;

import com.gggd.aopdemo.anno.Desensitization;
import com.gggd.aopdemo.anno.Desensitize;
import com.gggd.aopdemo.util.WebApiResult;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Collection;

/**
 * @Description
 * @Author srx
 * @date 2021/12/25 13:29
 */
@Aspect
@Component
public class DesensitizationAspect {

    /**
     * 声明一个切入点
     */
    @Pointcut("@annotation(com.gggd.aopdemo.anno.Desensitization)")
    private void desensitizePointcut() {}


    /**
     * 切入操作
     * @param result 方法的返回体
     */
    @AfterReturning(pointcut = "desensitizePointcut()", returning = "result")
    public void check(JoinPoint joinPoint, Object result){
        try {
            //获取被切入的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取被切入方法上的注解
            Desensitization annotation = signature.getMethod().getAnnotation(Desensitization.class);
            //获取注解的value：field
            String field = annotation.field();
            //判断field是否为空，为空则返回的是一个对象或者集合
            if("".equals(field)){
                //判断是否为集合并脱敏
                isCollection(result);
            }else {
                //获取注解的value：dataClass
                Class dataClass = annotation.DataClass();
                //获取字段列表
                Field[] fields = dataClass.getDeclaredFields();
                //创建一个标志位，判断是否存在需要脱敏的字段
                boolean is = true;
                for (Field f : fields) {
                    //获取到需要脱敏的字段
                    if(f.getName().equals(field)){
                        is = false;
                        f.setAccessible(true);
                        Object o = f.get(result);
                        //判断是否为集合并脱敏
                        isCollection(o);
                    }
                }
                //未找到需要脱敏的字段，抛出异常
                if(is){
                    throw new RuntimeException("The field could not be found:" + field);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断是否为集合并进行脱敏
     * @param result
     * @throws IllegalAccessException
     */
    private void isCollection(Object result) throws IllegalAccessException{
        //判断是否为集合
        if(result instanceof Collection){
            Collection collection = (Collection) result;
            for (Object o : collection){
                desensitize(o);
            }
        }else {
            desensitize(result);
        }
    }

    /**
     * 进行脱敏类型判断
     * @param o
     * @throws IllegalAccessException
     */
    private void desensitize(Object o) throws IllegalAccessException{
        //获取对象的全部字段
        Field[] fields = o.getClass().getDeclaredFields();
        //迭代字段
        for(Field f : fields ){
            //判断字段是否存在@Desensitize注解
            if(f.isAnnotationPresent(Desensitize.class)){
                //注解存在，设置字段为可修改
                f.setAccessible(true);
                //获取注解的类型值
                Desensitize desensitize = f.getAnnotation(Desensitize.class);
                String value = String.valueOf(desensitize.type());
                //对值进行判断，启动相应的脱敏规则
                switch (value){
                    case "PHONE" :
                        //对手机号进行脱敏
                        desensitizePhone(f, o);
                        break;
                    case "IDCARD" :
                        //对身份证进行脱敏
                        desensitizeIDCard(f, o);
                        break;
                    case "NAME" :
                        //对姓名进行脱敏
                        desensitizeName(f, o);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    /**
     * 脱敏手机号
     * @param f
     * @param o
     * @throws IllegalAccessException
     */
    private void desensitizePhone(Field f, Object o) throws IllegalAccessException{
        //获取字段的值
        String phone = (String) f.get(o);
        //判断值是否为空
        if(StringUtils.isNotEmpty(phone)){
            if(phone.length() == 11){
                //通过正则表达式将手机号中间4位替换为*号
                String newTel = phone.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2");
                //将值设置为修改后的值
                f.set(o, newTel);
            }
        }
    }

    /**
     * 脱敏身份证
     * @param f
     * @param o
     * @throws IllegalAccessException
     */
    private void desensitizeIDCard(Field f, Object o) throws IllegalAccessException{
        //获取字段的值
        String idCard = (String) f.get(o);
        //判断值是否为空
        if (StringUtils.isNotEmpty(idCard)) {
            //对身份证号进行过脱敏操作
            if (idCard.length() == 15){
                idCard = idCard.replaceAll("(\\w{6})\\w*(\\w{3})", "$1******$2");
            }
            if (idCard.length() == 18){
                idCard = idCard.replaceAll("(\\w{6})\\w*(\\w{3})", "$1*********$2");
            }
            //将值设置为修改后的值
            f.set(o, idCard);
        }
    }

    /**
     * 脱敏姓名
     * @param f
     * @param o
     * @throws IllegalAccessException
     */
    private void desensitizeName(Field f, Object o) throws IllegalAccessException{
        //获取字段的值
        String name = (String) f.get(o);
        //判断值是否为空且长度是否大于2位
        if (StringUtils.isNotEmpty(name) && name.length() >= 2) {
            //对姓名进行过脱敏操作
            String newName = "";
            if(name.length() == 2){
                newName = StringUtils.left(name, 1) + "*";
            }else{
                String start = "";
                for (int i = 0; i < name.length() - 2; i++) {
                    start += "*";
                }
                newName = name.replaceAll(name.substring(1, name.length() - 1), start);
            }
            //将值设置为修改后的值
            f.set(o, newName);
        }
    }
}
